﻿// Copyright (c) ZhangPeihang. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using BootstrapBlazor.Components;
using LaserMark.Components.Events;
using LaserMark.Components.Layout;
using LaserMark.Components.Services;
using LaserMark.Components.Utils;
using LaserMark.Control.Service;
using LaserMark.Extensions;
using LaserMark.Models;
using LaserMark.View.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System.Timers;

namespace LaserMark.Components;

/// <summary>
///
/// </summary>
public partial class AxisJog : EventComponentBase
{
    [Inject]
    [NotNull]
    private IControl? Control { get; set; }


    [Parameter]
    [NotNull]
    public Original? Original { get; set; }

    [Inject]
    [NotNull]
    private IGlobalStatus? GlobalStatus { get; set; }

    [Inject]
    [NotNull]
    private IOptions<MarkOption>? Options { get; set; }

    [NotNull]
    private MarkOption? MarkOption { get; set; }

    [Inject]
    [NotNull]
    private IStringLocalizer<MainLayout>? Localizer { get; set; }

    [CascadingParameter(Name = "Ribbon")]
    [NotNull]
    private List<RibbonTabItem>? Items { get; set; }

    private bool IsShow { get; set; }

    private Color ArrowColor { get; set; } = Color.Primary;

    private bool IsArrow { get; set; }

    private Color ReseveColor { get; set; } = Color.Primary;

    private Color Mock { get; set; } = Color.Primary;

    private bool IsMock { get; set; }

    private bool IsReseve { get; set; }

    private double XPos { get; set; }

    private double YPos { get; set; }

    private double ZPos { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        MarkOption = Options.Value;
    }
    protected override async Task OnParametersSetAsync()
    {
        await base.OnParametersSetAsync();

        mc.GT_GetDi(0, mc.MC_GPI, out int value);
        var aa = Convert.ToString(value, 2).PadLeft(16);
        if (aa[12] == '1')
            IsShow = true;
        CommandNames.Add(RibbonTabConstants.AutoOrManual);

        System.Timers.Timer timer = new(500);
        timer.Elapsed += TimerHander;
        timer.Start();
    }

    private void TimerHander(object? sender, ElapsedEventArgs e)
    {
        mc.GT_GetDi(0, mc.MC_GPI, out int value);
        var aa = Convert.ToString(value, 2).PadLeft(16);
        if (aa[12] == '1')
            IsShow = true;
        else
            IsShow = false;
        InvokeAsync(StateHasChanged);
    }

    private async Task OnJog(double axis, double vel, double acc, double dec, bool isNav = false)
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            double b = 0;
            if (axis == MarkOption.AxisCode.X)
            {
                b = 1000 / (1 / MarkOption.XPluse.Value);
            }

            if (axis == MarkOption.AxisCode.Y)
            {
                b = 1000 / (1 / MarkOption.YPluse.Value);
            }

            if (axis == MarkOption.AxisCode.Z)
            {
                b = 1000 / (1 / MarkOption.ZPluse.Value);
            }

            vel = vel / b;
            var trap = new mc.TJogPrm();
            trap.acc = acc / 10000;
            trap.dec = dec / 10000;
            if (isNav)
            {
                vel = -vel;
            }
            await Control.SetPrfJog(0, (short)axis, (int)vel, ref trap);
        }
    }

    private async Task OnStop(int axis)
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            mc.GT_SetVel(0, (short)axis, 0);
            mc.GT_Update(0, 1 << (axis - 1));
            await Task.Delay(500);
            await Control.Stop(0, 1 << (axis - 1), 0);
        }
    }

    private async Task OnTransforArrow()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            if (!IsArrow)
            {
                IsArrow = true;
                ArrowColor = Color.Danger;
                await Control.SetDoBit(0, mc.MC_GPO, 10, 0);
                await Task.Delay(MarkOption.ComprehensiveSetting.TransUpDelay);
                await Control.SetDoBit(0, mc.MC_GPO, 8, 0);
            }
            else
            {
                IsArrow = false;
                await Control.SetDoBit(0, mc.MC_GPO, 8, 1);
                await Task.Delay(MarkOption.ComprehensiveSetting.TransDownDelay);
                await Control.SetDoBit(0, mc.MC_GPO, 10, 1);
                ArrowColor = Color.Primary;
            }
            StateHasChanged();
        }
    }


    private async Task OnTransforReseve()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            if (!IsReseve)
            {
                IsReseve = true;
                ReseveColor = Color.Danger;
                await Control.SetDoBit(0, mc.MC_GPO, 10, 0);
                await Task.Delay(1000);
                await Control.SetDoBit(0, mc.MC_GPO, 9, 0);
            }
            else
            {
                IsReseve = false;
                await Control.SetDoBit(0, mc.MC_GPO, 9, 1);
                await Task.Delay(1000);
                await Control.SetDoBit(0, mc.MC_GPO, 10, 1);
                ReseveColor = Color.Primary;
            }
            StateHasChanged();
        }

    }

    private async Task OnPtPX()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            var b = 1000 / (1 / MarkOption.XPluse.Value);
            var trap = new mc.TTrapPrm();
            trap.acc = MarkOption.ManualAcc.X / 10000;
            trap.dec = MarkOption.ManualDec.X / 10000;
            trap.smoothTime = 49;
            await Control.SetPTP(0, (short)MarkOption.AxisCode.X, (int)(MarkOption.ManualVel.X / b), XPos / MarkOption.XPluse.Value, ref trap);
        }
    }

    private async Task OnStopX()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            await Control.Stop(0, 1 << ((short)MarkOption.AxisCode.X - 1), 0);
        }
    }

    private async Task OnPtPY()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            var b = 1000 / (1 / MarkOption.YPluse.Value);
            var trap = new mc.TTrapPrm();
            trap.acc = 0.1;
            trap.dec = 0.1;
            await Control.SetPTP(0, (short)MarkOption.AxisCode.Y, (int)(MarkOption.ManualVel.Y / b), YPos / MarkOption.YPluse.Value, ref trap);
        }
    }

    private async Task OnStopY()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            await Control.Stop(0, 1 << ((short)MarkOption.AxisCode.Y - 1), 1 << ((short)MarkOption.AxisCode.Y - 1));
        }
    }

    private async Task OnPtPZ()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            var b = 1000 / (1 / MarkOption.ZPluse.Value);
            var trap = new mc.TTrapPrm();
            trap.acc = 0.1;
            trap.dec = 0.1;
            await Control.SetPTP(0, (short)MarkOption.AxisCode.Z, (int)(MarkOption.ManualVel.Z / b), ZPos / MarkOption.ZPluse.Value, ref trap);
        }
    }

    private async Task OnStopZ()
    {
        if (!GlobalStatus.IsEmergencyStop)
        {
            await Control.Stop(0, 1 << ((short)MarkOption.AxisCode.Z - 1), 1 << ((short)MarkOption.AxisCode.Z - 1));
        }
    }

    protected override void OnRegisterEvent()
    {
        var maul = new RibbonTabEvent(RibbonTabConstants.AutoOrManual, ((e) =>
        {
            IsShow = !IsShow;
            StateHasChanged();
            return Task.CompletedTask;
        }));

        Events.Add(maul);
        EventBus.RegisterHandler(maul);
    }

    private async Task OnZero()
    {
        await Control.ZeroPos(0, 2, 1);
        await Control.ZeroPos(0, 3, 1);
        await Control.ZeroPos(0, 4, 1);
    }

    [NotNull]
    private AutoResetEvent? AutoResetEvent { get; set; } = new(true);

    [NotNull]
    private CancellationTokenSource? Token { get; set; } = new();

    private Task OnMockClick()
    {
        if (!IsMock)
        {
            IsMock = true;
            Mock = Color.Danger;
            Token ??= new();
            _ = Task.Run(async () =>
            {
                while (IsMock)
                {
                    if (AutoResetEvent.WaitOne())
                    {
                        AutoResetEvent.Reset();
                        await CreateMockCrd.Create(Original, MarkOption);
                        short run = 0;
                        do
                        {
                            if (GlobalStatus.IsEmergencyStop)
                            {
                                Token.Cancel();
                                Token.Dispose();
                                Token = null;
                                IsMock = false;
                                Mock = Color.Primary;
                                await Control.Stop(0, 1 << 8, 1 << 8);
                                await InvokeAsync(StateHasChanged);
                            }

                            mc.GT_CrdStatus(0, 1, out run, out _, 0);
                        } while (run == 1);

                        if (run != 1)
                        {
                            AutoResetEvent.Set();
                        }
                    }
                }
            }, cancellationToken: Token.Token);
            StateHasChanged();
        }
        else
        {
            Token.Cancel();
            Token.Dispose();
            Token = null;
            IsMock = false;
            Mock = Color.Primary;
            StateHasChanged();
        }

        return Task.CompletedTask;
    }
}
